package org.bookshare.document.daisy;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.benetech.collections.IdTree;
import org.benetech.event.EventListener;
import org.benetech.util.FileUtils;
import org.bookshare.document.navigation.NavigationElement;
import org.bookshare.document.navigation.NavigationElement.NavigationElementType;
import org.jdom.Attribute;
import org.jdom.DocType;
import org.jdom.Document;
import org.jdom.Element;

/**
 * A class to generate and handle a SMIL file.
 * TODO, the richness of the SMIL can be improved.
 * TODO, audio is not currently handled.
 * TODO, we do not currently list elements in playback order, but rather they are categorized by navigation type.
 * @author Reuben Firmin
 */
public final class SMILNavigationFile {

	private Document smilDocument;
	private File smilFile;
	private final Map<String, NavigationElement> idMap = new HashMap<String, NavigationElement>();

	/**
     * Given relevant data, generate a SMIL file for a DAISY book.
     * @param xmlBook wrapper around the xml document
     * @param opf wrapper around the OPF
     * @param tmpPath A temporary path to create the file in
     * @param eventListener Class to provide feedback to the user
     * @throws IOException if file access fails
     */
    public SMILNavigationFile(final File tmpPath, final DTBook xmlBook, final OPFPackageFile opf,
    		final EventListener eventListener)
    throws IOException
    {
    	smilDocument = new Document();
    	smilDocument.setDocType(new DocType("smil", "-//NISO//DTD dtbsmil 2005-2//EN",
    			"http://www.daisy.org/z3986/2005/dtbsmil-2005-2.dtd"));
    	final Element root = new Element("smil");
        smilDocument.setRootElement(root);
        final Element head = new Element("head");
        root.addContent(head);
        final Element uid = new Element("meta");
        uid.getAttributes().add(new Attribute("name", "uid"));
        uid.getAttributes().add(new Attribute("content", "Bookshare-" + opf.getISBN()));
        head.addContent(uid);
        final Element title = new Element("meta");
        title.getAttributes().add(new Attribute("name", "title"));
        title.getAttributes().add(new Attribute("content", opf.getMetadataMap().getFirst("title").getTextTrim()));
        head.addContent(title);
        final Element body = new Element("body");
        root.addContent(body);
        body.addContent(generateSeq(xmlBook.getPrimaryNavigationType(), xmlBook.getPrimaryNavigation(), xmlBook));
        for (Map.Entry<NavigationElementType, List<NavigationElement>> secondary
        		: xmlBook.getSecondaryNavigation().entrySet())
        {
        	body.addContent(generateSeq(secondary.getKey(), secondary.getValue(), xmlBook));
        }

        final String smilName = opf.getBaseName() + ".smil";
        this.smilFile = new File(tmpPath.getAbsolutePath() + File.separator + smilName);
        eventListener.message("Creating SMIL file: " + smilFile.getAbsolutePath());
        FileUtils.saveDocumentToFile(smilDocument, smilFile, true);
    }

    /**
     * Generate seq element from the description, tree of pars.
     * @param pars The pars
     * @param xmlBook The book
     * @return Never null
     */
    private Element generateSeq(final NavigationElementType element, final List<NavigationElement> pars,
    		final DTBook xmlBook)
    {
    	final Element seq = new Element("seq");
    	for (NavigationElement parNode : pars) {
	    	final Element par = new Element("par");
	        seq.addContent(par);
	        par.getAttributes().add(new Attribute("id", parNode.getId()));
	        idMap.put(parNode.getId(), parNode);
	        final Element text = new Element("text");
	        par.addContent(text);
	        text.getAttributes().add(new Attribute("region", "text"));
	        text.getAttributes().add(new Attribute("src", xmlBook.getXMLFile().getName() + "#" + parNode.getId()));
        }
        seq.getAttributes().add(new Attribute("id", element.toString()));
        return seq;
    }

    /**
     * Get the generated SMIL document.
     * @return Never null
     */
    public Document getSMILDocument() {
    	return smilDocument;
    }

    /**
     * Get the generated SMIL file.
     * @return Never null.
     * @return
     */
    public File getSMILFile() {
    	return smilFile;
    }

    /**
     * Get the element mapped to the given id.
     * @param id The id that the element is mapped to
     * @return Never null
     */
    public NavigationElement getElementById(String id) {
    	return idMap.get(id);
    }
}
